{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 5 - Saving, updating and exporting the map widget"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc": true
   },
   "source": [
    "<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
    "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Saving-a-web-map\" data-toc-modified-id=\"Saving-a-web-map-1\">Saving a web map</a></span></li><li><span><a href=\"#Updating-a-web-map\" data-toc-modified-id=\"Updating-a-web-map-2\">Updating a web map</a></span></li><li><span><a href=\"#Export-live-map-in-a-separate-HTML-file\" data-toc-modified-id=\"Export-live-map-in-a-separate-HTML-file-4\">Export live map in a separate HTML file</a></span></li><li><span><a href=\"#Rendering-Web-Map-items-on-a-Map-object\" data-toc-modified-id=\"Rendering-Web-Map-items-on-a-Map-object-5\">Rendering Web Map items on a Map object</a></span></li><li><span><a href=\"#Conclusion\" data-toc-modified-id=\"Conclusion-6\">Conclusion</a></span></li></ul></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Saving a web map\n",
    "\n",
    "Starting with the Python API version 1.3, you can save the map widget as a web map in your `GIS`. This process persists the basemaps, layers added (with or without your custom symbology, including smart mapping), pop-ups, extent, and graphics drawn (with or without custom symbols) as layers in your `web map`.\n",
    "\n",
    "To save the map, call the `save()` method. This method creates and returns a new `Web Map Item` object. As parameters, you can specify all valid Item properties as shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from arcgis.gis import GIS\n",
    "from arcgis.map import Map\n",
    "gis = GIS(profile=\"your_online_profile\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<FeatureLayer url:\"https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Countries/FeatureServer/0\">"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "world_countries_item = gis.content.get('ac80670eb213440ea5899bbf92a04998')\n",
    "world_countries_layer = world_countries_item.layers[0]\n",
    "world_countries_layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<img src=\"\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map1 = gis.map(\"USA\")\n",
    "map1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "map1.content.add(world_countries_layer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Item title:\"World Countries 2024-September\" type:Web Map owner:arcgis_python>\n"
     ]
    }
   ],
   "source": [
    "webmap_properties = {'title':'World Countries 2024-September',\n",
    "                     'snippet': 'Jupyter notebook widget saved as a web map',\n",
    "                     'tags':['automation', 'python']}\n",
    "\n",
    "webmap_item = map1.save(webmap_properties, thumbnail=r\".\\webmap_thumbnail.PNG\")\n",
    "print(webmap_item)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Updating a web map\n",
    "\n",
    "Similarly, if you created the `Map` object from an existing web map item, you can call the `update()` method to update it.\n",
    "\n",
    "Note, the `save()` method always creates a new item with an updated web map definition, so this is a great way to create a copy of an existing web map. For instance, the cell below calls the `save()` method and creates a new web map item with the new set of layers, without disturbing the original web map item."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can search for web maps just like any other item:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"item_container\" style=\"height: auto; overflow: hidden; border: 1px solid #cfcfcf; border-radius: 2px; background: #f6fafa; line-height: 1.21429em; padding: 10px;\">\n",
       "                    <div class=\"item_left\" style=\"width: 210px; float: left;\">\n",
       "                       <a href='https://geosaurus.maps.arcgis.com/home/item.html?id=ede4f15af5ac4290bb5d38e8167c0189' target='_blank'>\n",
       "                        <img src='' width='200' height='133' class=\"itemThumbnail\">\n",
       "                       </a>\n",
       "                    </div>\n",
       "\n",
       "                    <div class=\"item_right\"     style=\"float: none; width: auto; overflow: hidden;\">\n",
       "                        <a href='https://geosaurus.maps.arcgis.com/home/item.html?id=ede4f15af5ac4290bb5d38e8167c0189' target='_blank'><b>02 Snow routes for first responders</b>\n",
       "                        </a>\n",
       "                        <br/>City and County of Denver snow routes,  along with Police and Fire Stations within the City and County of Denver.<br/><img src='https://geosaurus.maps.arcgis.com/home/js/jsapi/esri/css/images/item_type_icons/maps16.png' style=\"vertical-align:middle;\" width=16 height=16>Web Map by EsriTrainingSvc\n",
       "                        <br/>Last Modified: March 11, 2024\n",
       "                        <br/>0 comments, 30606 views\n",
       "                    </div>\n",
       "                </div>\n",
       "                "
      ],
      "text/plain": [
       "<Item title:\"02 Snow routes for first responders\" type:Web Map owner:EsriTrainingSvc>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "webmap_search = gis.content.search(\"Snow routes for first responders\", item_type=\"Web Map\", outside_org=True)\n",
    "snow_routes_item = webmap_search[0]\n",
    "snow_routes_item"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also create a `Map` object from an existing web map item by passing the web map item as the parameter to the constructor:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Snow Routes\n",
      "Fire Stations\n",
      "Police Stations\n"
     ]
    }
   ],
   "source": [
    "snow_routes_map = Map(snow_routes_item)\n",
    "for layer in snow_routes_map.content.layers:\n",
    "    print(layer.properties['name'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can update a web map by adding or removing layers. For instance, the cell below removes one of the layers from the web map and adds a different layer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# remove the first - unclassed layer from the map\n",
    "snow_routes_map.content.remove(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "snow_routes_map.content.add(world_countries_layer, options={'title':'World Countries'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Snow Routes\n",
      "Police Stations\n",
      "World_Countries\n"
     ]
    }
   ],
   "source": [
    "for layer in snow_routes_map.content.layers:\n",
    "    print(layer.properties['name'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let's add a layer to the existing `map1` and update the web map item:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<FeatureLayer url:\"https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Countries/FeatureServer/0\">\n",
      "<FeatureLayer url:\"https://services.arcgis.com/ue9rwulIoeLEI9bj/arcgis/rest/services/Snow_routes_for_first_responders_WFL1/FeatureServer/1\">\n"
     ]
    }
   ],
   "source": [
    "from arcgis.features import FeatureLayer\n",
    "map1.content.add(FeatureLayer(\"https://services.arcgis.com/ue9rwulIoeLEI9bj/arcgis/rest/services/Snow_routes_for_first_responders_WFL1/FeatureServer/1\"), )\n",
    "\n",
    "for layer in map1.content.layers:\n",
    "    print(layer)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the `save` method will create a new web map item, while using the `update` method will make updates to the previous web map item:\n",
    "\n",
    "```\n",
    "update(item_properties=None, thumbnail=None, metadata=None)\n",
    "```\n",
    "The `update` method uses the following parameters:\n",
    "\n",
    "        ---------------     --------------------------------------------------------------------\n",
    "        item_properties     Optional dictionary. See table below for the keys and values.\n",
    "        ---------------     --------------------------------------------------------------------\n",
    "        thumbnail           Optional string. Either a path or URL to a thumbnail image.\n",
    "        ---------------     --------------------------------------------------------------------\n",
    "        metadata            Optional string. Either a path or URL to the metadata.\n",
    "        ---------------     --------------------------------------------------------------------\n",
    "        \n",
    "The `update` method will update the Web Map item that was used to create the `Map` object. In addition, you are also able to update the item's other properties, thumbnail, and metadata. Please review the `Scene.update()` method within the [Scene class](https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#arcgis.map.Scene.update) to update a Scene item."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "webmap_item_properties = {'title':'Fire Stations in Denver',\n",
    "                          'snippet':'Map created using Python API showing fore stations in Denver against the world map',\n",
    "                          'tags':['automation', 'safety', 'python']}\n",
    "\n",
    "new_map_item = map1.update(item_properties = webmap_item_properties, \n",
    "                           thumbnail='./webmap_thumbnail.png')\n",
    "print(new_map_item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Item title:\"Fire Stations in Denver\" type:Web Map owner:arcgis_python>\n"
     ]
    }
   ],
   "source": [
    "# We can see from the output that the title is being updated:\n",
    "print(webmap_item)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Export live map in a separate HTML file\n",
    "\n",
    "Another new feature in 1.5.0 is the ability to export the current widget as a stand-alone HTML file. This added functionality provides a new workflow for creating standalone HTML maps that can be shared with anyone. All they need is a web browser!\n",
    "\n",
    "The cell below will write the current widget to the file specified by a string path. Run the cell, find the file on your disk, and open it in your favorite web browser.\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "  <b>Note:</b> By default, only publicly accessible layers will show on the exported HTML maps. You must specify that `credentials_prompt=True` to allow users to authenticate to the GIS to view private layers. See the API reference for more information.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "html saved as D:\\Projects\\arcgis-python-api\\guide\\10-mapping-and-visualization\\home\\myWorldMap.html\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "file_dir = os.path.join(os.getcwd(), 'home')\n",
    "if not os.path.isdir(file_dir):\n",
    "    os.mkdir(file_dir)\n",
    "    \n",
    "file_path = os.path.join(file_dir, 'myWorldMap.html')\n",
    "\n",
    "map1.export_to_html(file_path)\n",
    "print(\"html saved as \" + file_path) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rendering Web Map items on a Map object\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "  <b>Note:</b> This is the first iteration of the new map widget and some backward compatability issues with rendering maps built against a previous version of the JSAPI can be expected. In order to resolve such issues, please open the map in the Map Viewer, and re-save it. This will make necessary updates to the JS specs of your map, in order to render them without errors.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<img src=\"\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map2 = gis.map(\"USA\")\n",
    "map2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "census_item = gis.content.get(\"85d0ca4ea1ca4b9abf0c51b9bd34de2e\")\n",
    "census_flayer = census_item.layers[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "map2.content.add(census_flayer)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "In Part 5 of this guide series, we observed how to consume web maps and web scenes and how to update them. During this process, the examples demonstrated how to modify the map widget using code, how to make copy of an existing item into your account, how to look for basemaps, and how to update layer properties within a web map.\n",
    "\n",
    "<a href=\"#Part-5---Saving,-embedding-and-exporting-the-map-widget\">Back to Top</a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": true,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
